import type { ImagePreviewConfig } from '../type';
import './style.css'

// 元素查询方法的绑定
const $ = document.querySelector.bind(document), $$ = document.querySelectorAll.bind(document);
// 默认配置对象
const defultConfig: ImagePreviewConfig = {
    selector: '[preview]', // 图片预览节点选择器
    appendSelector: 'body', // 弹出层的插入dom节点的选择器
    clickDialogClose: true, // 点击蒙版是否关闭弹出框

    class: { // 设置的各个html表的class
        class_image_wrapper: 'image-wrapper',
        class_image_content: "image-preview",
        class_dialog_wrapper: 'dialog-wrapper',
        class_action_wrapper: 'action-wrapper',
        class_operate_icon: 'operate-icon',
        class_close_icon: 'close-icon',
    },
    actionConfig: {
        zoomStep: 0.2,  // 放大、缩小倍数
        minScale: 0.2,  // 最小 缩小倍数
        maxScale: 2,    // 最大 缩小倍数
        rotateStepDeg: 90, // 每次旋转的旋转角度
        rotateBack: false, // 旋转360度时是否重置为0度
    },
    actionVisibleConfig: { // 操作按钮的显示和隐藏
        zoomIn: true,
        zoomOut: true,
        rotateLeft: true,
        rotateRight: true,
    },
    icons: { // 操作按钮的 图片路径(base64格式)
        zoomIn: '',
        zoomOut: '',
        rotateLeft: '',
        rotateRight: '',
        close: '',
    }
}

const config: ImagePreviewConfig = {};
// 设置用户配置
function initConfig(userConf = {}) {
    Object.assign(config, defultConfig, userConf);
    bindEvent();
}

function previewImage(imageUrl:string){
    return DialogOperator.openDialog(imageUrl);
}

// 事件绑定-事件委托
function bindEvent() {
    $('body').addEventListener('click', function (event) {
        const target = event.target;
        // 点击预览图片
        if (target.matches(config.selector)) {
            return previewImage(target.src);
        }
        // 点击遮罩层-关闭dialog
        if (config.clickDialogClose && (target.classList.contains(config.class?.class_dialog_wrapper) || target.classList.contains(config.class?.class_image_wrapper))) {
            return target.classList.contains(config.class?.class_dialog_wrapper) ? DialogOperator.closeDialog(target) : DialogOperator.closeDialog(target.parentElement);
        }

        // 点击操作按钮
        if (target.classList.contains(config?.class?.class_operate_icon)) {
            const imageNode = target.parentElement.parentElement.querySelector(`img.${config?.class?.class_image_content}`);
            const typeName = target.getAttribute('name');
            if (typeName == 'zoomIn') {
                return ImageOperator.ZoomIn(imageNode);
            }
            if (typeName == 'zoomOut') {
                return ImageOperator.ZoomOut(imageNode);
            }
            if (typeName == 'rotateLeft') {
                return ImageOperator.rotateLeft(imageNode);
            }
            if (typeName == 'rotateRight') {
                return ImageOperator.rotateRight(imageNode);
            }
            // 点击关闭按钮
            if (typeName == 'close') {
                return DialogOperator.closeDialog(imageNode.parentElement.parentElement);
            }
        }
    })
}

// 弹出框操作
const DialogOperator = {
    openDialog(imagePath:string) {
        // 已经创建了则直接替换
        if ($(`${config.appendSelector}>.${config?.class?.class_dialog_wrapper}`)) {
            const dialogWrapper = $(`${config.appendSelector}>.${config?.class?.class_dialog_wrapper}`);
            const imageElement = dialogWrapper.querySelector(`img.${config?.class?.class_image_content}`);
            imageElement.src = imagePath;
            dialogWrapper.style.display = 'block';
            return;
        }

        // 没有则新建
        const dialogWrapper = document.createElement('div');
        dialogWrapper.classList.add(config?.class?.class_dialog_wrapper || '');
        dialogWrapper.innerHTML = `
            <div class='${config?.class?.class_image_wrapper}'>
                <img src='${imagePath}' draggable="false" alt="preview" class="${config?.class?.class_image_content}"/>
                <div class='${config?.class?.class_operate_icon} ${config?.class?.class_close_icon}' style='background-image: url(${config?.icons?.close})' name='close'></div>
                <div class='${config?.class?.class_action_wrapper}'>
                    ${Object.entries(config?.actionVisibleConfig || {}).filter(([key, value]) => value).map(([key, value]) => `
                            <div class='${config?.class?.class_operate_icon}' name='${key}' style='background-image: url(${config.icons![key] || ''})'></div>
                        `).join('')
            }
                </div>
            <div>
        `
        $(config.appendSelector).appendChild(dialogWrapper);
    },

    closeDialog(dialogDom:HTMLElement) {
        const imageElement = dialogDom.querySelector(`img.${config?.class?.class_image_content}`) as HTMLElement;
        imageElement.style.transform = ''; //变换样式重置
        dialogDom.style.display = 'none';
    },

    desotryDialog(dialogDom:HTMLElement) {
        this.closeDialog(dialogDom);
        dialogDom.remove();
    }
}


// CSS 的transform字符串和对象的转换， 如 scale(1.2) rotate(90deg) 变为 { scale: '1.2', rotate: '90deg' };
const cssTransformUtil = {
    regExp: /(\w+)\(\s*(-?\w*\.?\w*)\s*\)/,
    getNumberOfString(str: string): number {
        let num = 0;
        if (!str) {
            return num;
        }
        const matches = String(str).match(/-?\d*\.?\d*/);
        if (matches) {
            num = Number(matches[0]);
        }
        return num;
    },
    pareStrToObj(str: string): any {
        const obj = {};
        if (str) {
            const arr = String(str).split(' ');
            arr.forEach(strItem => {
                const matches = strItem.match(this.regExp);
                if (matches) {
                    const [, key, value] = matches;
                    obj[key.trim()] = value.trim();
                }
            })
        }
        return obj;
    },
    stringfyObj(obj:any) {
        return Object.entries(obj).map(([key, val]) => `${key}(${val})`).join(' ');
    },
}

// 图片操作对象
const ImageOperator = {
    ZoomIn(imageNode:HTMLElement) {
        const transformObj = cssTransformUtil.pareStrToObj(imageNode.style.transform);
        let preScale = cssTransformUtil.getNumberOfString(transformObj.scale) || 1;
        let scaleNum = preScale + config?.actionConfig?.zoomStep!;
        if (preScale < config?.actionConfig?.maxScale!) {
            transformObj.scale = scaleNum;
            imageNode.style.transform = cssTransformUtil.stringfyObj(transformObj);
        }
    },

    ZoomOut(imageNode:HTMLElement) {
        const transformObj = cssTransformUtil.pareStrToObj(imageNode.style.transform);
        let preScale = cssTransformUtil.getNumberOfString(transformObj.scale) || 1;
        let scaleNum = preScale - config.actionConfig!.zoomStep!;
        if (preScale > config.actionConfig!.minScale!) {
            transformObj.scale = scaleNum;
            imageNode.style.transform = cssTransformUtil.stringfyObj(transformObj);
        }
    },

    rotateLeft(imageNode:HTMLElement) {
        const transformObj = cssTransformUtil.pareStrToObj(imageNode.style.transform);
        let preRotate = cssTransformUtil.getNumberOfString(transformObj.rotate) || 0;
        let rotateDeg = config.actionConfig!.rotateBack ?
            (preRotate - config.actionConfig!.rotateStepDeg!) % 360 : (preRotate - config.actionConfig!.rotateStepDeg!);
        transformObj.rotate = rotateDeg + 'deg';
        imageNode.style.transform = cssTransformUtil.stringfyObj(transformObj);
    },

    rotateRight(imageNode:HTMLElement) {
        const transformObj = cssTransformUtil.pareStrToObj(imageNode.style.transform);
        let preRotate = cssTransformUtil.getNumberOfString(transformObj.rotate) || 0;
        let rotateDeg = config.actionConfig!.rotateBack! ?
            (preRotate + config.actionConfig!.rotateStepDeg!) % 360 : (preRotate + config.actionConfig!.rotateStepDeg!);
        transformObj.rotate = rotateDeg + 'deg';
        imageNode.style.transform = cssTransformUtil.stringfyObj(transformObj);
    },
}



export default {
    initConfig, 
    previewImage,
}
